package org.ykh.srb.core.controller;

import io.swagger.v3.oas.annotations.ExternalDocumentation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.ykh.service.exception.BusinessException;
import org.ykh.srb.core.pojo.entity.DictEntity;
import org.ykh.srb.core.service.DictService;
import org.ykh.service.result.Result;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * <p>
 * 数据字典 前端控制器
 * </p>
 *
 * @author ykh
 * @since 2024-03-12
 */
@RestController
@CrossOrigin
@RequestMapping("/dict")
@Tag(
        name = "DictControllerAPI",
        description = "dict控制器接口",
        externalDocs = @ExternalDocumentation(description = "文档详情略")
)
public class DictController{

    private final DictService dictService;

    private final RedisTemplate<String, Object> redisTemplate;

    public DictController(DictService dictService, RedisTemplate<String, Object> redisTemplate) {
        this.dictService = dictService;
        this.redisTemplate = redisTemplate;
    }

//    private final ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
    //使用接口，应对未来实现替换（比如分布式锁）
    private final ReadWriteLock rw = new ReentrantReadWriteLock();

    @Operation(
            summary = "根据Id查询dict信息",
            description = "根据ID查询dict信息，并返回响应结果信息"
    )
    @ApiResponse(
            responseCode = "200",
            description = "响应成功",
            content = @Content(
                    mediaType = "application/json",
                    schema = @Schema(
                            title = "获取dict",
                            description = "获取dict",
                            implementation = Result.class
                    )
            )
    )
    @GetMapping("/{id}")
    public Result<DictEntity> getDict(
            @Parameter(description = "字典ID", example = "1", required = true)
            @PathVariable("id") Integer id) {
        rw.readLock().lock();
        DictEntity dictEntity;
        try {
            dictEntity = (DictEntity) redisTemplate.opsForValue().get("dict:" + id);
            if (dictEntity != null) {
                return Result.ok(dictEntity);
            }
        } finally {
            rw.readLock().unlock();
        }
        //防止大量请求进入，缓存雪崩，缓存击穿
        rw.writeLock().lock();
        try {
            dictEntity = (DictEntity) redisTemplate.opsForValue().get("dict:" + id);
            if (dictEntity == null) {
                dictEntity = dictService.getById(id);
                //无论数据库中是否存在都在redis中存一份，防止缓存穿透。设置3分钟自动过期
                redisTemplate.opsForValue().set("dict:" + id, dictEntity,3,TimeUnit.MINUTES);
            }
            return Result.ok(dictEntity);
        } finally {
            rw.writeLock().unlock();
        }
    }

    @Operation(
            summary = "根据id更新dict",
            description = "根据id更新dict"
    )
    @ApiResponse(
            responseCode = "200",
            description = "响应成功",
            content = @Content(
                    mediaType = "application/json",
                    schema = @Schema(
                            title = "更新dict",
                            description = "更新dict",
                            implementation = Result.class
                    )
            )
    )
    @PostMapping("/modify")
    public Result<?> modifyDict(
            @RequestBody DictEntity dictEntity) {
        rw.writeLock().lock();
        try {
            dictService.updateById(dictEntity);
            redisTemplate.delete("dict:" + dictEntity.getId());
            return Result.ok();
        } finally {
            rw.writeLock().unlock();
        }
    }


    @Operation(
            summary = "上传excel",
            description = "根据ID查询dict信息，并返回响应结果信息"
    )

    @ApiResponse(
            responseCode = "200",
            description = "响应成功",
            content = @Content(
                    mediaType = "application/json",
                    schema = @Schema(
                            title = "上传excel",
                            description = "上传excel",
                            implementation = Result.class
                    )
            )
    )
    @PostMapping("/uploading")
    public Result<?> uploading(
            @Parameter(description = "文件", example = "文件流", required = true)
            @RequestPart("file") MultipartFile file) {
        try {
            dictService.importData(file.getInputStream());
            return Result.ok();
        } catch (IOException e) {
            throw new BusinessException("30001", "excel导入失败");
        }
    }


    @Operation(
            summary = "下载excel",
            description = "下载excel"
    )
    @GetMapping("/export")
    public void export(HttpServletResponse response) {
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("mydict", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            dictService.exportData(response.getOutputStream());
        } catch (IOException exception) {
            throw new BusinessException("3002", "下载失败");
        }
    }

}
